/**
  ******************************************************************************
  * @file    main.c
  * @author  MCU Application Team
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by Puya under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "myTasks.h"
#include "segment_LED.h"

/* Private define ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
LCD_HandleTypeDef LCD_Handle;
FLASH_OBProgramInitTypeDef OB_init_cfg;

struct SegmentLED_stu lcd_p1 = {
    .segment_pin_map = mySegLED_pin_map_1,
    .write_seg_pin = mySegLED_write_seg_pin,
};

struct SegmentLED_stu lcd_p2 = {
    .segment_pin_map = mySegLED_pin_map_2,
    .write_seg_pin = mySegLED_write_seg_pin,
};

struct SegmentLED_stu lcd_p3 = {
    .segment_pin_map = mySegLED_pin_map_3,
    .write_seg_pin = mySegLED_write_seg_pin,
};

struct SegmentLED_stu lcd_p4 = {
    .segment_pin_map = mySegLED_pin_map_4,
    .write_seg_pin = mySegLED_write_seg_pin,
};

struct SegmentLED_stu *lcd_p[] = {
    [0] = &lcd_p1,
    [1] = &lcd_p2,
    [2] = &lcd_p3,
    [3] = &lcd_p4,
};

/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void APP_SystemClockConfig(void);
void my_LCD_init(void);
void my_GPIO_init(void);
void alarm_cb_debounce(void *param);

/**
  * @brief  Main program.
  * @retval int
  */
int main(void)
{
  /* Reset of all peripherals, Initializes the Systick. */
  HAL_Init();
  
  /* System clock configuration */
  APP_SystemClockConfig(); 

    // 初始化 rtt
    SEGGER_RTT_Init();
    LOG_STR("\n\nSYSTEM START\n\n");

    // flash 读保护
#if 1
    HAL_FLASH_OBGetConfig(&OB_init_cfg);
    LOG_FMT(PRINT_DEBUG"RDP Level 0x%02x\r\n", (uint32_t)(OB_init_cfg.RDPLevel));
    if(OB_init_cfg.RDPLevel == OB_RDP_LEVEL_0){ // 读保护未开启，自动开启
        LOG_FMT(PRINT_DEBUG"Opening RDP...\n");
        HAL_Delay(500);
        
        HAL_FLASH_Unlock();    // 解锁FLASH
        HAL_FLASH_OB_Unlock(); // 解锁FLASH OPTION
        OB_init_cfg.RDPLevel = OB_RDP_LEVEL_1;
        HAL_FLASH_OBProgram(&OB_init_cfg);
        HAL_FLASH_Lock();
        HAL_FLASH_OB_Lock();

        HAL_FLASH_OB_Launch();
    }
#endif
  
    // 初始化段码屏
    my_LCD_init();
    // 初始化引脚
    my_GPIO_init();

    // 显示时钟源
    my_lcd_clean_all();
    SEG_LED_show_num(&lcd_p1, SEG_LED_NUM_8);
    lcd_p1.write_seg_pin(&lcd_p1, SEG_LED_SEGMENT_A, 1);
    lcd_p1.write_seg_pin(&lcd_p1, SEG_LED_SEGMENT_D, 1);

    SEG_LED_show_num(&lcd_p2, SEG_LED_NUM_5);

    if(__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_HSE){
        LOG_STR("Using HSE\n");
        SEG_LED_show_num(&lcd_p3, SEG_LED_NUM_E);
    }else if(__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_SYSCLKSOURCE_STATUS_PLLCLK){
        LOG_STR("Using PLL\n");
        SEG_LED_show_num(&lcd_p1, SEG_LED_NUM_8);
        lcd_p1.write_seg_pin(&lcd_p1, SEG_LED_SEGMENT_C, 1);
        lcd_p1.write_seg_pin(&lcd_p1, SEG_LED_SEGMENT_D, 1);

        SEG_LED_show_num(&lcd_p2, SEG_LED_NUM_C);
        lcd_p2.write_seg_pin(&lcd_p2, SEG_LED_SEGMENT_F, 0);
        lcd_p2.write_seg_pin(&lcd_p2, SEG_LED_SEGMENT_G, 1);

        SEG_LED_show_num(&lcd_p3, SEG_LED_NUM_C);
        lcd_p3.write_seg_pin(&lcd_p3, SEG_LED_SEGMENT_F, 0);
        lcd_p3.write_seg_pin(&lcd_p3, SEG_LED_SEGMENT_G, 1);

    }else {
        LOG_STR("Using HSI\n");
        SEG_LED_show_num(&lcd_p3, SEG_LED_NUM_1);
    }

    my_lcd_refresh();

    // 初始化自定义任务
    myTask_init();
  
    // 计算开机用时
    UsType_t us = rtx_Sys_get_us();
    LOG_FMT("\nReaction force tester init over in %d.%03dms.\n", rtx_Sys_get_tick(), us);

    // 延迟时钟源显示内容
    HAL_Delay(500);

    // 显示 TiX
    my_lcd_clean_all();

    SEG_LED_show_num(&lcd_p1, SEG_LED_NUM_7);
    lcd_p2.write_seg_pin(&lcd_p2, SEG_LED_SEGMENT_A, 0);
    lcd_p2.write_seg_pin(&lcd_p2, SEG_LED_SEGMENT_E, 0);
    lcd_p2.write_seg_pin(&lcd_p2, SEG_LED_SEGMENT_F, 0);
    SEG_LED_show_num(&lcd_p3, SEG_LED_NUM_1);
    SEG_LED_show_num(&lcd_p4, SEG_LED_NUM_8);
    lcd_p2.write_seg_pin(&lcd_p4, SEG_LED_SEGMENT_A, 1);
    lcd_p2.write_seg_pin(&lcd_p4, SEG_LED_SEGMENT_D, 1);

    my_lcd_refresh();
    
    // 清除按键事件标志位，避免开机按键抖动造成的事件触发
    topic_tester.flag = 0;
    // 手动初始化按键，避免丢失第一次按下
    alarm_cb_debounce(NULL);

    rtx_Sys_schedule_start(); // 开启调度
    
    rtx_Sys_scheduler(); // 运行调度器
  
  /* Infinite loop */
  while (1)
  {
    
  }
}

/**
  * @brief  System clock configuration function
  * @param  None
  * @retval None
  */
static void APP_SystemClockConfig(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /* Oscillator configuration */
#if defined(RCC_LSE_SUPPORT)
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE; /* Select oscillator HSE, HSI, LSI, LSE */
#else
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSI; /* Select oscillator HSE, HSI, LSI */
#endif
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;                          /* Enable HSI */
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;                          /* HSI 1 frequency division */
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_8MHz;  /* Configure HSI clock 8MHz */
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;                         /* Close HSE */
  RCC_OscInitStruct.HSEFreq = RCC_HSE_8_16MHz;
  RCC_OscInitStruct.LSIState = RCC_LSI_OFF;                         /* Close LSI */
#if defined(RCC_LSE_SUPPORT)
  RCC_OscInitStruct.LSEState = RCC_LSE_OFF;                         /* Close LSE */
  /*RCC_OscInitStruct.LSEDriver = RCC_LSEDRIVE_MEDIUM;*/
#endif
//   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_OFF;                     /* Close PLL */
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;                     /* Close PLL */
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL3;
  /* Configure oscillator */
  HAL_StatusTypeDef ret_osc_init = HAL_RCC_OscConfig(&RCC_OscInitStruct);
  if (ret_osc_init != HAL_OK)
  {
    LOG_FMT(PRINT_ERROR"RCC OSC config ERROR: %d\n", ret_osc_init);
    APP_ErrorHandler();
  }

  /* Clock source configuration */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1; /* Choose to configure clock HCLK, SYSCLK, PCLK1 */
//   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; /* Select HSISYS as the system clock */
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; /* Select HSISYS as the system clock */
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;     /* AHB clock 1 division */
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;      /* APB clock 1 division */
  /* Configure clock source */
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    LOG_STR(PRINT_ERROR"RCC clock config ERROR!\n");
    APP_ErrorHandler();
  }
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void APP_ErrorHandler(void)
{
    LOG_STR("\n\nSYSTEM ERROR\n\n");
  /* Infinite loop */
  while (1)
  {
  }
}


void my_LCD_init(void){
    /* Initialize LCD */
    LCD_Handle.Instance = LCD;
    LCD_Handle.Init.Contrast = LCD_CONTRASTLEVEL_0;
    LCD_Handle.Init.BiasSrc = LCD_BIAS_SRC_IN_RES_HIGH_POWER;
    LCD_Handle.Init.Duty = LCD_DUTY_1_4;
    LCD_Handle.Init.Bias = LCD_BIAS_1_3;
    LCD_Handle.Init.ScanFre = LCD_SCAN_FRE_128HZ;
    LCD_Handle.Init.Mode = LCD_MODE_0;
    if (HAL_LCD_Init(&LCD_Handle) != HAL_OK)
    {
      APP_ErrorHandler();
    }
    
    /* Set SEG COM output */
    LCD_SegComTypeDef LcdSegCom;
    LcdSegCom.Seg0_13 = 0xffffff00;                            /* Configure LCD_POEN0 register to enable SEG0~SEG7 */
    LcdSegCom.Seg14_17_Com0_7_t.Seg14_17_Com0_7 = 0xffffffff;  /* Initialize LCD_POEN1 register, all output ports closed */
    LcdSegCom.Seg14_17_Com0_7_t.SegComBit.Com0_3 = 0;          /* Enable COM0~COM3 */
    if (HAL_LCD_SetSegCom(&LCD_Handle, &LcdSegCom) != HAL_OK)
    {
      APP_ErrorHandler();
    }
    
    /* Display "88:88" on the LCD */
    // HAL_LCD_Write(&LCD_Handle, LCD_RAM_REGISTER0, 0x0f0f0f0f);
    // HAL_LCD_Write(&LCD_Handle, LCD_RAM_REGISTER1, 0x0f0f0f0f);
}

void my_GPIO_init(void){
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    // led 引脚
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_15;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_15, 1);
    
    // 按键引脚
    GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitStructure.Pull = GPIO_PULLUP;
    GPIO_InitStructure.Pin = GPIO_PIN_3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);

    HAL_NVIC_SetPriority(EXTI2_3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI2_3_IRQn);
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     for example: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* Infinite loop */
  while (1)
  {
  }
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT Puya *****END OF FILE******************/
